package cate.game.activity;

import cate.common.game.GameCollection;
import cate.common.table.d.GDHistory;
import cate.common.table.d.GDObj;
import cate.game.GameBody;
import cate.game.activity.base.core.ActivityHandler;
import cate.game.activity.base.core.RoleActivitySingle;
import cate.game.activity.base.core.RoleFuncActivitySingle;
import cate.game.activity.diamondbowl.DiamondBowlActivity;
import cate.game.activity.firstpay.SuperFirstPayPO;
import cate.game.activity.herodirectbuy.HeroDirectBuyPO;
import cate.game.activity.Foodgod.FoodGodActivity;
import cate.game.activity.luckycharm.RoleLuckyCharm;
import cate.game.activity.merge.MergeActOverall;
import cate.game.role.Role;
import cate.game.role.RolePart;
import cate.game.role.merge.IRoleMergeSettle;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.util.time.TimeCostRecord;
import easy.java.dev.note.NoteField;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Document(GameCollection.NAME_ROLE_ACTIVITY)
public class RoleActivity extends RolePart implements IRoleMergeSettle {
    @NoteField("超值首充")
    public SuperFirstPayPO superFirstPay;

    @NoteField("合服活动")
    public MergeActOverall mergeActOverall;

    @NoteField("天降锦鲤")
    public RoleLuckyCharm luckyCharm;

    @NoteField("个人活动数据")
    public Map<Integer, RoleActivitySingle> singles;

    public RoleActivity() {
    }

    public RoleActivity(Role role) {
        super(role);
    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        // 超值首充
        if (superFirstPay == null) {
            superFirstPay = new SuperFirstPayPO();
        }
        superFirstPay.initialize(role);
        if (mergeActOverall == null) {
            mergeActOverall = new MergeActOverall();
        }
        mergeActOverall.initialize(role);
        if (luckyCharm == null) {
            luckyCharm = new RoleLuckyCharm();
        }
        luckyCharm.initialize(role);
        if (singles == null) {
            singles = new HashMap<>();
        }
        for (ActivityHandler<?, ?> handler : role.getGame().activityGlobal.handlers.values()) {
            if (!singles.containsKey(handler.getFuncId())) {
                RoleActivitySingle single = handler.buildSingle();
                single.init(handler.getFuncId());
                singles.put(handler.getFuncId(), single);
            } else {
                RoleActivitySingle ss = singles.get(handler.getFuncId());
                if (!ss.getClass().equals(handler.getSingleType())) {
                    logger.warn("[RoleActivityPO] 活动改变了实现类! {} -> {}",
                            ss.getClass().getName(), handler.getSingleType());
                    RoleActivitySingle single = handler.buildSingle();
                    single.init(handler.getFuncId());
                    singles.put(handler.getFuncId(), single);
                }
            }
        }
        rechargeConsumers.clear();
        singles.values().forEach(single -> {
            try {
                single.initialize(role);
                single.excelCheck();
            } catch (Exception e) {
                logger.error("", e);
            }
        });
    }

    @Override
    public void onEnter() {
        super.onEnter();
        singles.values().forEach(RoleActivitySingle::onEnterSafe);
        checkOpen();
    }

    @Override
    public void onDaySpan(boolean silence) {
        superFirstPay.onDaySpanSafe(silence);
        singles.values().stream().filter(RoleActivitySingle::enable)
                .forEach(single -> single.onDaySpanSafe(silence));
        luckyCharm.onDaySpanSafe(silence);
    }

    @Override
    public void onWeekSpan(boolean silence) {
        singles.values().forEach(single -> single.onWeekSpanSafe(silence));
    }

    @Override
    public void onMonthSpan(boolean silence) {
        singles.values().forEach(single -> single.onMonthSpanSafe(silence));
    }

    /**
     * 初始化发送包
     */
    public void initSend() {
        singles.values().stream()
                .filter(RoleActivitySingle::needInitSend)
                .forEach(RoleActivitySingle::initSend);
        mergeActOverall.noticeUpdate();
        luckyCharm.noticeUpdate();
    }

    public void tick() {
        singles.values().forEach(RoleActivitySingle::tick);
    }

    @Override
    protected void offline() {
        singles.values().forEach(RoleActivitySingle::offlineSafe);
    }

    @Override
    public void onMergeSettle(GameBody game, TimeCostRecord tcr) {
        singles.values().forEach(single -> {
            tcr.start(String.format("[funcId=%d] 合服处理开始", single.funcId));
            single.onMergeSettle();
            tcr.start(String.format("[funcId=%d] 合服处理结束", single.funcId));
        });
    }

    /**
     * 获取玩家活动数据
     * 未开启的活动也可获得
     *
     * @param funcId 功能ID
     */
    @Transient
    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <SINGLE extends RoleActivitySingle> SINGLE getActivitySingle(int funcId) {
        try {
            if (singles.containsKey(funcId)) {
                return (SINGLE) singles.get(funcId);
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取开启的玩家活动数据
     *
     * @param funcId 功能ID
     */
    @Transient
    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <SINGLE extends RoleActivitySingle> SINGLE getEnableActivitySingle(int funcId) {
        try {
            if (singles.containsKey(funcId)) {
                SINGLE single = (SINGLE) singles.get(funcId);
                if (single.base.active()) {
                    return single;
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取单类活动项
     *
     * @param clazz 活动个人类
     */
    @Transient
    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <SINGLE extends RoleActivitySingle> List<SINGLE> getList(Class<SINGLE> clazz) {
        return singles.values().stream().filter(single -> single.getClass().equals(clazz))
                .map(single -> (SINGLE) single)
                .collect(Collectors.toList());
    }

    /**
     * 获取单类活动开启项
     *
     * @param clazz 活动个人类
     */
    @Transient
    @JsonIgnore
    @SuppressWarnings("unchecked")
    public <SINGLE extends RoleActivitySingle> List<SINGLE> getEnableList(Class<SINGLE> clazz) {
        return singles.values().stream().filter(single -> single.getClass().equals(clazz))
                .filter(RoleActivitySingle::enable)
                .map(single -> (SINGLE) single)
                .collect(Collectors.toList());
    }

    /**
     * 获取需求判断功能开启的活动开启项
     */
    @Transient
    @JsonIgnore
    public List<RoleFuncActivitySingle> getFuncEnableList() {
        return singles.values().stream().filter(single -> RoleFuncActivitySingle.class.isAssignableFrom(single.getClass()))
                .filter(RoleActivitySingle::enable)
                .map(single -> (RoleFuncActivitySingle) single)
                .collect(Collectors.toList());
    }

    @Transient
    @JsonIgnore
    @NoteField("充值触发")
    private final Map<Integer, Consumer<Long>> rechargeConsumers = new HashMap<>();

    /**
     * 注册充值回调
     *
     * @param single 活动个人类
     * @param consumer 充值回调
     */
    public void registerRecharge(RoleActivitySingle single, Consumer<Long> consumer) {
        if (consumer == null || single == null) {
            return;
        }
        rechargeConsumers.put(single.funcId, consumer);
    }

    /**
     * 充值
     *
     * @param paySum 充值数额
     */
    public void onRecharge(long paySum) {
        rechargeConsumers.forEach((funcId, consumer) -> {
            if (getEnableActivitySingle(funcId) != null) {
                consumer.accept(paySum);
            }
        });
    }

    /**
     * 活动功能开启检测
     */
    public void checkOpen() {
        getFuncEnableList().forEach(RoleFuncActivitySingle::checkOpen);
    }

    public void doRecord(int event, int param, long num) {
        if (event == GDHistory.Event.COST_RES_VALUE) {
            if (param == GDObj.Num.M1) {
                // 英雄直购记录消耗钻石
                getEnableList(HeroDirectBuyPO.class).forEach(single -> single.consumeAdd(num));
                // 聚宝盆记录消耗钻石
                getEnableList(DiamondBowlActivity.class).forEach(single -> single.onConsumeDiamond(num));
                getEnableList(FoodGodActivity.class).forEach(single -> single.onConsumeM1(num));
            }
        }
    }
}
